package com.hm.hall.commons.service;


import com.hm.hall.commons.dao.ConsoleConfigMapper;
import com.hm.hall.commons.domain.ConsoleConfigExample;
import com.hm.hall.commons.util.AnnotationDefinitionUtils;
import com.hm.hall.commons.util.JsonUtils;
import com.hm.hall.commons.constans.ConsoleConfigKeysConstants;
import com.hm.hall.commons.domain.ConsoleConfig;
import com.hm.hall.commons.util.ActionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.regex.Pattern;


/**
 * 配置项service类
 *
 * @author Administrator
 */
@Component
@Transactional
public class ConsoleConfigService {
    /**
     * 配置项管理缓存
     */
    public static final String CACHE_ALL_CONFIG_PREFIX = "config-cache:all-config";
    public static String CONSOLE_CONFIG_VALUE_REDIS_KEY = "SYS_CFG_V_KEY_";
    public static String CONSOLE_CONFIG_OBJECT_REDIS_KEY = "SYS_CFG_O_KEY_";
    static Logger log = Logger.getLogger(ConsoleConfigService.class);
    private static boolean IS_CONSOLE_CONFIG_INIT = false;
    @Autowired
    RedisCacheService redisCacheService;
    @Autowired
    ConsoleConfigMapper consoleConfigMapper;

    {
        initConsoleConfigDB();
    }


    /**
     * 另开一个线程去初始化,清理,配置表,  异常的话 忽略
     */
    public void initConsoleConfigDB() {
        if (ConsoleConfigService.IS_CONSOLE_CONFIG_INIT) {
            return;
        }
        ConsoleConfigService.IS_CONSOLE_CONFIG_INIT = true;
        new Thread() {
            @Override
            public void run() {
                try {
                    ActionUtils.sleep(7000);
                    Map<Object, ConsoleConfig> mapConfig = ConsoleConfigKeysConstants.getConfigInstance();
                    for (ConsoleConfig consoleConfig : mapConfig.values()) {
                        if (findByKey(consoleConfig.getCkey()) == null) {
                            save(consoleConfig);
                        }
                    }
                    // 初始化更新下缓存里的的配置
                    for (ConsoleConfig consoleConfig : findAll()) {
                        syncCacheCfg(consoleConfig);
                    }
                    // 清理 DB中多出来的 配置   ,不清理了,怕旧版本的 把新版本的配置给删除了
//                    int curDbCfgCount = consoleConfigMapper.countByExample(new ConsoleConfigExample());
//                    if (curDbCfgCount != mapConfig.size()) {
//                        List<ConsoleConfig> curDbCfgAll = consoleConfigMapper.selectByExample(new ConsoleConfigExample());
//                        List<ConsoleConfig> curJavaCfgAll = new ArrayList<ConsoleConfig>(mapConfig.values());
//                        for (ConsoleConfig curDbCfg : curDbCfgAll) {
//                            boolean isExist = false;
//                            for (ConsoleConfig curJavaCfg : curJavaCfgAll) {
//                                if (StringUtils.equals(curDbCfg.getCkey(), curJavaCfg.getCkey())) {
//                                    isExist = true;
//                                }
//                            }
//                            if (!isExist) {
//                                consoleConfigMapper.deleteByPrimaryKey(curDbCfg.getConfigId());
//                            }
//                        }
//                    }

                } catch (Exception e) { // 初始化失败不管
                    log.info("initConsoleConfigDB.ERROR :" + e.getMessage());
                }
                super.run();
            }
        }.start();
    }


    /**
     * 注意要用此方法,更新配置, 因为要同步缓存中的数据
     *
     * @param consoleConfig
     * @return
     */
    public int save(ConsoleConfig consoleConfig) {
        syncCacheCfg(consoleConfig);
        return consoleConfigMapper.insertSelective(consoleConfig);
    }

    // 同步缓存里的配置信息
    private void syncCacheCfg(ConsoleConfig consoleConfig) {
        AnnotationDefinitionUtils an = ConsoleConfigKeysConstants.getAnnotationDefinitionUtilsByKey(consoleConfig.getCkey());
        if (an == null) {
            return;
        }

        String cacheObjKey = CONSOLE_CONFIG_OBJECT_REDIS_KEY + consoleConfig.getCkey();
        redisCacheService.setex(cacheObjKey, an.cacheSec(), JsonUtils.toJSONString(consoleConfig));

        String cacheKey = CONSOLE_CONFIG_VALUE_REDIS_KEY + consoleConfig.getCkey();
        redisCacheService.setex(cacheKey, an.cacheSec(), consoleConfig.getCval());
    }


    public ConsoleConfig findByKey(String key) {
        ConsoleConfigExample example = new ConsoleConfigExample();
        example.or().andCkeyEqualTo(key);
        List<ConsoleConfig> consoleConfigs = consoleConfigMapper.selectByExample(example);
        return !consoleConfigs.isEmpty() ? consoleConfigs.get(0) : null;
    }

    /**
     * 用key 获得值,会读缓存(缓存60分钟)
     *
     * @param key
     * @return
     */
    public String getValueByCache(String key) {
        AnnotationDefinitionUtils an = ConsoleConfigKeysConstants.getAnnotationDefinitionUtilsByKey(key);
        if (an == null) {
            return null;
        }

        String cacheKey = CONSOLE_CONFIG_VALUE_REDIS_KEY + key;
        String cVal = redisCacheService.get(cacheKey);
        if (cVal == null) {
            ConsoleConfig cfg = findByKey(key);
            // 缓存N分钟
            if (cfg != null) {
                cVal = cfg.getCval();
                redisCacheService.setex(cacheKey, an.cacheSec(), cVal);
            }
        }
        return cVal;
    }


    /**
     * 用key 获得配置对象,会读缓存(缓存60分钟)
     *
     * @param key
     * @return
     */
    public ConsoleConfig findByKeyCache(String key) {
        AnnotationDefinitionUtils an = ConsoleConfigKeysConstants.getAnnotationDefinitionUtilsByKey(key);
        if (an == null) {
            return null;
        }

        String cacheKey = CONSOLE_CONFIG_OBJECT_REDIS_KEY + key;
        String cfgJSON = redisCacheService.get(cacheKey);
        ConsoleConfig consoleConfig;
        if (cfgJSON != null) {
            consoleConfig = JsonUtils.parseObject(cfgJSON, ConsoleConfig.class);
        } else {
            consoleConfig = findByKey(key);
            // 缓存N分钟
            if (consoleConfig != null) {
                redisCacheService.setex(cacheKey, an.cacheSec(), JsonUtils.toJSONString(consoleConfig));
            }
        }
        return consoleConfig;
    }


    /**
     * @return 所有配置
     */
    @Transactional(readOnly = true)
    public List<ConsoleConfig> findAll() {
        ConsoleConfigExample example = new ConsoleConfigExample();
        example.setOrderByClause("sort");
        return consoleConfigMapper.selectByExample(example);
    }


    /**
     * 根据目录查找
     *
     * @param dir        dir
     * @param strKeyLike 查询串
     * @return lst config
     */
    @Transactional(readOnly = true)
    public List<ConsoleConfig> findByDir(String dir, String strKeyLike) {
        List<ConsoleConfig> lst = findAll();
        List<ConsoleConfig> lstNew = new ArrayList<>();
        for (ConsoleConfig conf : lst) {
            String ckey = conf.getCkey();
            String dirTemp = StringUtils.isEmpty(dir) ? "" : dir + ".";
            if (Pattern.matches("^" + dirTemp.replaceAll("\\.", "\\\\.") + "[^\\.]*", ckey) && !ckey.substring(dirTemp.length()).contains(".")) {// 模拟LLIKE
                if (StringUtils.isEmpty(strKeyLike)) {
                    lstNew.add(conf);
                } else if (Pattern.matches(".*" + strKeyLike + ".*", ckey)) {
                    lstNew.add(conf);
                }
            }
        }
        return lstNew;
    }


    /**
     * 根据配置项查询配置
     *
     * @return List<Config>
     */
    public List<ConsoleConfig> findConfig() {
        Map<Object, ConsoleConfig> map = ConsoleConfigKeysConstants.getConfigInstance();
        Iterator<Map.Entry<Object, ConsoleConfig>> iterator = map.entrySet().iterator();
        List<ConsoleConfig> lstConfig = new ArrayList<>();
        while (iterator.hasNext()) {
            Map.Entry<Object, ConsoleConfig> entry = iterator.next();
            if (null != entry.getKey()) {
                ConsoleConfig config = findByKey(String.valueOf(entry.getKey()));
                if (null == config) {
                    config = entry.getValue();
                } else {
                    config.setCnName(entry.getValue().getCnName());
                    config.setShowType(entry.getValue().getShowType());
                    config.setCgroup(entry.getValue().getCgroup());
                    config.setRemarks(entry.getValue().getRemarks());
                }
                lstConfig.add(config);
            }
        }
        Collections.sort(lstConfig, new Comparator<ConsoleConfig>() {
            @Override
            public int compare(ConsoleConfig o1, ConsoleConfig o2) {
                return o1.getSort() > o2.getSort() ? 1 : -1;
            }
        });
        return lstConfig;
    }


}
